#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>

#include "serverPaul.h"

/*
 * Note: bad error handling so sometimes strange messages are printed
 */

int clients[MAXCLIENTS];
char names[MAXCLIENTS][MAXNAME];

void addClient(int socket)
{
	int i;
	for (i=0;i<MAXCLIENTS;i++)
	{
		if(clients[i] == 0)
		{
			clients[i] = socket;
			/*
			 * How do you know you have read everything?
			 */
			read(socket,&(names[i][0]),MAXNAME);
			printf("Adding client no %d, name %s, pos %d\n",socket,names[i],i);
			return;
		}
	}
	
	char *message = "Server full.\n";
	write(socket,message,strlen(message));
	close(socket);
}

void removeClient(int socket)
{
	printf("Removing client no %d\n",socket);
	int i;
	for (i=0;i<MAXCLIENTS;i++)
	{
		if(clients[i] == socket)
		{
			clients[i] = 0;
			close(socket);
			return;
		}
	}
}


void sendMessage(int socket)
{
	int i, readsize;
	int nameidx;
	char message[MAXLINE];
	char sendmessage[MAXLINE+MAXNAME+2];
	readsize = read(socket,&message,MAXLINE);

	if (readsize == -1)
	{
		removeClient(socket);
		return;
	}
	
	for(i=0; i<MAXCLIENTS; i++)
	{
		if(clients[i] == socket)
		{
			nameidx = i;
			break;
		}
	}
	
	sprintf(sendmessage,"%s: %s",names[nameidx],message);	

	for(i=0; i<MAXCLIENTS; i++)
	{
		if(clients[i] != 0)
		{
			printf("numero de cliente %d \n",clients[i]);
			printf("%s\n", sendmessage);
			if(write(clients[i], &sendmessage, strlen(sendmessage)) == -1)
				removeClient(clients[i]);
		}
	}
}

void logTime()
{
	/*
	 * time_t time(time_t *tloc);
	 * "returns the value of time in seconds since 0 hours, 0
     * minutes, 0 seconds, January 1, 1970, Coordinated Universal Time, without
     * including leap seconds."
	 *
	 * return value is also stored in *tloc, if tloc != non-null, returns -1 on error
	 *
	 * Note: time_t is signed 32 bit value. Will overflow in 2038: the Y2K38 problem
	 */
	time_t now;
	now = time(NULL);
	
	/*
	 * struct tm *localtime(const time_t *clock);
	 *
	 * see time.h for struct tm
	 */	
	struct tm *nowstruct;
	nowstruct = localtime(&now);
	
	printf("---%02d:%02d:%02d---\n",nowstruct->tm_hour,nowstruct->tm_min,nowstruct->tm_sec);
}

int main()
{
	int listener;
	
	if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket open error");
		return(EXIT_FAILURE);
	}
	
	struct sockaddr_in listener_address;
	listener_address.sin_family = AF_INET;
	listener_address.sin_port = htons(PORT);
	listener_address.sin_addr.s_addr = htonl(ACCEPT_SERVER);
	int socklen = sizeof(listener_address);
	
	if(bind(listener,(struct sockaddr *)&listener_address,socklen)!= 0)
	{
		perror("bind error");
		close(listener);
		return(EXIT_FAILURE);
	}
	
	if(listen(listener,5)!=0)
	{
		perror("listen error");
		close(listener);
		return(EXIT_FAILURE);
	}
	
	
	int i;
	for(i=0;i<MAXCLIENTS;i++)
		clients[i]=0;
	
	printf("Listening for connections\n");

	logTime();
	
	/*
	 * time in seconds and microseconds:
	 * struct timeval {
	 *	time_t tv_sec;
	 *	long tv_usec;
	 * }
	 */

	struct timeval timeout;
	fd_set sockets;
	int ready;
	
	while(1)
	{
		FD_ZERO(&sockets);
		FD_SET(listener,&sockets);
		
		/*
		 * 'good style to re-initialize [timeout] before each invocation of select()'
		 */
		timeout.tv_sec = 4;
		timeout.tv_usec = 500000;
		
		for(i=0; i<MAXCLIENTS; i++)
			FD_SET(clients[i],&sockets);
		
		/*
		 * FD_SETSIZE = maximum size of fd_set
		 */

		ready = select(FD_SETSIZE,&sockets,NULL,NULL,&timeout);

		if(ready == -1)
		{
			perror("select error");
		}
		else if (ready != 0) 
		{

			if(FD_ISSET(listener,&sockets))
			{
				int sock;
				sock = accept(listener,NULL,NULL);
				if(sock == -1)
				{
					perror("accept error");
					close(sock);
				}
				else
					addClient(sock);
			}

			else
			/* if somebody wrote*/
				for(i=0; i<MAXCLIENTS; i++)
				{
					if(FD_ISSET(clients[i],&sockets))
						sendMessage(clients[i]);
				}
					
		}
		else /* ready = 0 -> timeout */
			logTime();
	}
	close(listener);
	
	return(EXIT_SUCCESS);
}
